﻿using System;
using System.Runtime.InteropServices;

namespace ETKCAN
{
    [StructLayout(LayoutKind.Sequential)]
    public struct ECAN
    {
        public uint acc_code;
        public uint acc_mask;
        public uint reserved;
        public byte filter;
        public byte timing0;
        public byte timing1;
        public byte mode;
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct CANFD
    {
        public uint acc_code;
        public uint acc_mask;
        public uint abit_timing;
        public uint dbit_timing;
        public uint brp;
        public byte filter;
        public byte mode;
        public UInt16 pad;
        public uint reserved;
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct can_frame
    {
        public uint can_id;  /* 32 bit MAKE_CAN_ID + EFF/RTR/ERR flags */
        public byte can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
        public byte __pad;   /* padding */
        public byte __res0;  /* reserved / padding */
        public byte __res1;  /* reserved / padding */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] data/* __attribute__((aligned(8)))*/;
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct canfd_frame
    {
        public uint can_id;  /* 32 bit MAKE_CAN_ID + EFF/RTR/ERR flags */
        public byte len;     /* frame payload length in byte */
        public byte flags;   /* additional flags for CAN FD,i.e error code */
        public byte __res0;  /* reserved / padding */
        public byte __res1;  /* reserved / padding */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
        public byte[] data/* __attribute__((aligned(8)))*/;
    };

    [StructLayout(LayoutKind.Explicit)]
    public struct ECAN_CHANNEL_INIT_CONFIG
    {
        [FieldOffset(0)]
        public uint can_type; //type:TYPE_CAN TYPE_CANFD

        [FieldOffset(4)]
        public ECAN can;

        [FieldOffset(4)]
        public CANFD canfd;
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct ECAN_Transmit_Data
    {
        public can_frame frame;
        public uint transmit_type;
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct ECAN_Receive_Data
    {
        public can_frame frame;
        public UInt64 timestamp;//us
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct ECAN_TransmitFD_Data
    {
        public canfd_frame frame;
        public uint transmit_type;
    };

    public struct DeviceInfo
    {
        public uint device_type;  //设备类型
        public uint channel_count;//设备的通道个数
        public DeviceInfo(uint type, uint count)
        {
            device_type = type;
            channel_count = count;
        }
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct ECAN_ReceiveFD_Data
    {
        public canfd_frame frame;
        public UInt64 timestamp;//us
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct ECAN_CHANNEL_ERROR_INFO
    {
        public uint error_code;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public byte[] passive_ErrData;
        public byte arLost_ErrData;
    } ;
  

    public class Define
    {
        public const int TYPE_CAN = 0;
        public const int TYPE_CANFD = 1;

        public const int ECAN_USBCAN_J1939 = 1;
        public const int ECAN_PCIE_CANFD_P200FD = 2;
        public const int ECAN_USBCANFD_U200FD = 3;
        public const int ECAN_USBCANFD_U200FDI = 4;
        public const int ECAN_USBCANFD_MINIFD = 5;

        public const int ECAN_VIRTUAL_DEVICE = 99;

        public const int STATUS_ERR = 0;
        public const int STATUS_OK = 1;
    };

    public class Method
    {
        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr ECAN_OpenDevice(uint device_type, uint device_index, uint reserved);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint ECAN_CloseDevice(IntPtr device_handle);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        // pInitConfig -> ECAN_CHANNEL_INIT_CONFIG
        public static extern IntPtr ECAN_InitCAN(IntPtr device_handle, uint can_index, IntPtr pInitConfig);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint ECAN_StartCAN(IntPtr channel_handle);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint ECAN_ResetCAN(IntPtr channel_handle);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        // pTransmit -> ECAN_Transmit_Data
        public static extern uint ECAN_Transmit(IntPtr channel_handle, IntPtr pTransmit, uint len);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        // pTransmit -> ECAN_TransmitFD_Data
        public static extern uint ECAN_TransmitFD(IntPtr channel_handle, IntPtr pTransmit, uint len);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint ECAN_GetReceiveNum(IntPtr channel_handle, byte type);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint ECAN_Receive(IntPtr channel_handle, IntPtr data, uint len, int wait_time = -1);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern uint ECAN_ReceiveFD(IntPtr channel_handle, IntPtr data, uint len, int wait_time = -1);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        // pErrInfo -> ECAN_CHANNEL_ERROR_INFO
        public static extern uint ECAN_ReadChannelErrInfo(IntPtr channel_handle, IntPtr pErrInfo);

        [DllImport("CanFdlib.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr GetIProperty(IntPtr device_handle);

    }

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int SetValueFunc(string path, string value);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate string GetValueFunc(string path, string value);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate IntPtr GetPropertysFunc(string path, string value);

    public struct IProperty
    {
        public SetValueFunc SetValue;
        public GetValueFunc GetValue;
        public GetPropertysFunc GetPropertys;
    };
}
